package com.sina.shop.manage.controller.storage.goods;

import com.sina.cloudstorage.SCSClientException;
import com.sina.cloudstorage.services.scs.SCS;
import com.sina.cloudstorage.services.scs.model.*;
import com.sina.cloudstorage.services.scs.transfer.internal.UploadPartRequestFactory;
import com.sina.shop.domain.goods.GoodsPhoto;
import com.sina.shop.manage.form.StorageForm;
import com.sina.shop.manage.storage.CloudStorageException;
import com.sina.shop.manage.storage.StorageBucketNotFoundException;
import com.sina.shop.util.DateUtils;
import com.sina.shop.util.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static com.sina.shop.util.FileUtils.dropPrefixSlope;

/**
 * 新浪云存储 管理器
 * <p>
 * 负责文档上传（分片上传）
 */
@Component("sinaStorageGoodsPhotoManager")
public class SinaStorageGoodsPhotoManager implements InitializingBean {

    private static final Logger LOG = LoggerFactory.getLogger(SinaStorageGoodsPhotoManager.class);

    // 表示文档处理的 用户组
    private UserIdGrantee IMGX;

    @Autowired
    private SCS sinaScs;

    @Autowired
    private Environment environment;

    @Override
    public void afterPropertiesSet() throws Exception {
        IMGX = new UserIdGrantee(environment.getProperty("sina.storage.userId.file"));
    }


    public GoodsPhoto uploadGoodsPhoto(StorageForm form, File videoFile) throws Exception {
        String bucket = environment.getProperty("sina.storage.file.bucket");
        GoodsPhoto goodsPhoto = null;
        try {
            if (!sinaScs.doesBucketExist(bucket)) {
                throw new StorageBucketNotFoundException(null,
                        String.format("sina cloud bucket[%s] not found", bucket));
            }
            String storagePath = getStoragePath(
                    form.getDirectory()
                    , form.getFile().getOriginalFilename());
            LOG.info("carousel file[{}] storage path : {}", videoFile, storagePath);


            InitiateMultipartUploadResult initiateMultipartUploadResult = sinaScs
                    .initiateMultipartUpload(bucket, storagePath);

            if (initiateMultipartUploadResult != null) {
                //分片上传
                List<PartETag> partETags = null;
                PutObjectRequest putObjectRequest = new PutObjectRequest(initiateMultipartUploadResult.getBucketName(),
                        initiateMultipartUploadResult.getKey(), videoFile);
                try {
                    long optimalPartSize = 5 * 1024 * 1024; //分片大小5M
                    UploadPartRequestFactory requestFactory = new UploadPartRequestFactory(putObjectRequest, initiateMultipartUploadResult.getUploadId()
                            , optimalPartSize);

                    partETags = uploadPartsInSeries(requestFactory);
                } catch (Exception e) {
                    throw e;
                } finally {
                    if (putObjectRequest.getInputStream() != null) {
                        try {
                            putObjectRequest.getInputStream().close();
                        } catch (Exception e) {
                            throw e;
                        }
                    }
                }

                //分片列表
                PartListing partList = sinaScs.listParts(new ListPartsRequest(initiateMultipartUploadResult.getBucketName(),
                        initiateMultipartUploadResult.getKey(),
                        initiateMultipartUploadResult.getUploadId()));
                //分片合并，完成上传
                ObjectMetadata objectMetadata = sinaScs.completeMultipartUpload(new CompleteMultipartUploadRequest(putObjectRequest.getBucketName(),
                        putObjectRequest.getKey(), initiateMultipartUploadResult.getUploadId(), partETags));
                if (objectMetadata != null) {
                    goodsPhoto = new GoodsPhoto();
                    //goodsPhoto.setCloudStorageAddress("http://sinacloud.net/" + bucket + "/" + storagePath);//地址
                    goodsPhoto.setUrl(storagePath);//云存储文件名字

                }
            }
        } catch (SCSClientException e) {
            LOG.error("video[{}] upload to {}{} failure.", videoFile, bucket, form.getDirectory(), e);
            throw new CloudStorageException(null, e.getMessage());
        }
        return goodsPhoto;
    }


    private List<PartETag> uploadPartsInSeries(UploadPartRequestFactory requestFactory) {

        final List<PartETag> partETags = new ArrayList<>();

        while (requestFactory.hasMoreRequests()) {
            UploadPartRequest uploadPartRequest = requestFactory.getNextUploadPartRequest();
            // Mark the stream in case we need to reset it
            InputStream inputStream = uploadPartRequest.getInputStream();
            if (inputStream != null && inputStream.markSupported()) {
                if (uploadPartRequest.getPartSize() >= Integer.MAX_VALUE) {
                    inputStream.mark(Integer.MAX_VALUE);
                } else {
                    inputStream.mark((int) uploadPartRequest.getPartSize());
                }
            }
            partETags.add(sinaScs.uploadPart(uploadPartRequest).getPartETag());
        }

        return partETags;
    }

    private String getStoragePath(String directoryPath, String fileName) {
        String extension;
        extension = FileUtils.getFileExtension(fileName);
        if (!"".equals(directoryPath) && !directoryPath.endsWith("/")) {
            directoryPath = directoryPath.concat("/");
        }
        if (directoryPath.startsWith("/")) {
            directoryPath = dropPrefixSlope(directoryPath);
        }

        directoryPath += DateUtils.LocalDateFormatter("yyyyMMdd");
        fileName = String.format("%s/%s%s"
                , directoryPath
                , UUID.randomUUID().toString()
                , extension);
        return dropPrefixSlope(fileName);
    }


    public void download(GoodsPhoto goodsPhoto, OutputStream out) throws Exception {

        String bucket = environment.getProperty("sina.storage.file.bucket");
        S3Object s3Obj = sinaScs.getObject(bucket, goodsPhoto.getUrl());
        InputStream in = s3Obj.getObjectContent();
        byte[] buf = new byte[1024];

        try {
            int count;
            while ((count = in.read(buf)) != -1) {
                if (Thread.interrupted()) {
                    throw new InterruptedException();
                }
                out.write(buf, 0, count);

            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    public void deleteGoodsPhoto(GoodsPhoto GoodsPhoto) {
        String bucket = environment.getProperty("sina.storage.file.bucket");
        try {
            if (GoodsPhoto != null) {
                sinaScs.deleteObject(bucket, GoodsPhoto.getUrl());
            }
        } catch (SCSClientException e) {
            throw new CloudStorageException(null, e.getMessage());
        }

    }
}
